#define _XOPEN_SOURCE 500  /* include pread,pwrite */
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <dlfcn.h>
#include <elf.h>
#include <unistd.h>
#include <errno.h>       
#include <sys/mman.h>
#include <android/log.h>
#include <jni.h>

#ifndef ENABLE_DEBUG
#define ENABLE_DEBUG 1
#define  LOG_TAG "HOOK"
#define  LOGD( fmt, args ... ) __android_log_print( ANDROID_LOG_DEBUG, LOG_TAG, fmt, ## args )
#define  LOGE( fmt, args ... ) __android_log_print( ANDROID_LOG_ERROR, LOG_TAG, fmt, ## args )
#define  LOGI( fmt, args ... ) __android_log_print( ANDROID_LOG_INFO, LOG_TAG, fmt, ## args )
#endif

typedef const void *MSImageRef;
void *(*MSFindSymbol)(MSImageRef image, const char *name);
MSImageRef(*MSGetImageByName)(const char *file);
void(*MSJavaHookMethod)(JNIEnv *jni, jclass _class, jmethodID methodID, void *function, void **result);
void(*MSHookFunction)(void *symbol, void *replace, void **result);
void(*MSJavaHookClassLoad)(JNIEnv *jni, const char *name, void(*callback)(JNIEnv *, jclass, void *), void *data);

//这个方法来自 android inject 用于获取地址
void* get_module_base(int pid, const char* module_name)
{
    FILE *fp;
    long addr = 0;
    char *pch;
    char filename[32];
    char line[1024];
    if (pid < 0) {
        /* self process */
        snprintf(filename, sizeof(filename), "/proc/self/maps", pid);
    }
    else {
        snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
    }
    fp = fopen(filename, "r");
    if (fp != NULL) {
        while (fgets(line, sizeof(line), fp)) {
            if (strstr(line, module_name)) {
                pch = strtok(line, "-");
                addr = strtoul(pch, NULL, 16);

                if (addr == 0x8000)
                    addr = 0;

                break;
            }
        }
        fclose(fp);
    }
    return (void *)addr;
}

//这个方法来自 android inject 用于获取地址
void* get_remote_addr(int target_pid, const char* module_name, void* local_addr)
{
    void* local_handle, *remote_handle;

    local_handle = get_module_base(-1, module_name);
    remote_handle = get_module_base(target_pid, module_name);

    LOGI("[+] get_remote_addr: local[%x], remote[%x]\n", local_handle, remote_handle);

    void * ret_addr = (void *)((uint32_t)local_addr + (uint32_t)remote_handle - (uint32_t)local_handle);

#if defined(__i386__)    
    if (!strcmp(module_name, "/system/lib/libc.so")) {
        ret_addr += 2;
    }
#endif    
    return ret_addr;
}

//hook方法
void* (*olddlsym)(void*  handle, const char*  symbol);
void* newdlsym(void*  handle, const char*  symbol) {
    // LOGD("the handle [0x%x] symbol name:%s",handle,symbol);
    return olddlsym(handle, symbol);
}
void* (*olddlopen)(const char* filename, int myflags);
void* newdlopen(const char* filename, int myflags) {
    // LOGD("the dlopen name :%s",filename);
    if(strstr(filename, "libmono") != NULL)
    {
    	LOGD("the dlopen name :%s",filename);
    }
    return olddlopen(filename, myflags);
}


int main()
{
	//声明各个变量存放地址
    void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr, *dlerror_addr;
    //获取dlopen地址
    dlopen_addr = get_remote_addr(getpid(), "/system/bin/linker", (void *)dlopen);
    LOGI("[+] dlopen_addr: [%x]", dlopen_addr);
    //hook dlopen方法  下面方法类似
    MSHookFunction((void*)dlopen_addr, (void*)newdlopen, (void**)&olddlopen);

    dlsym_addr = get_remote_addr(getpid(), "/system/bin/linker", (void *)dlsym);
    LOGI("[+] dlsym_addr: [%x]", dlsym_addr);
    MSHookFunction(dlsym_addr, (void*)newdlsym, (void**)&olddlsym);
    dlclose_addr = get_remote_addr(getpid(), "/system/bin/linker", (void *)dlclose);
    dlerror_addr = get_remote_addr(getpid(), "/system/bin/linker", (void *)dlerror);
}
   

__attribute__((__constructor__)) static void _MSInitialize()
{
	LOGD("*************************************");
    void* handlesubdsub = dlopen("/system/lib/tools/libsubstrate.so", RTLD_NOW);
    void* handlesubdvm = dlopen("/system/lib/tools/libsubstrate-dvm.so", RTLD_NOW);
    if (handlesubdsub != NULL)
    {
        LOGD("***start dlsym methond***");
        MSGetImageByName = (MSImageRef(*)(const char *file))dlsym(handlesubdsub, "MSGetImageByName");
        MSFindSymbol = (void*(*)(MSImageRef image, const char *name))dlsym(handlesubdsub, "MSFindSymbol");
        MSHookFunction = (void(*)(void *symbol, void *replace, void **result))dlsym(handlesubdsub, "MSHookFunction");
        MSJavaHookClassLoad = (void(*)(JNIEnv *jni, const char *name, void(*callback)(JNIEnv *, jclass, void *), void *data))dlsym(handlesubdvm, "MSJavaHookClassLoad");
        MSJavaHookMethod = (void(*)(JNIEnv *jni, jclass _class, jmethodID methodID, void *function, void **result)) dlsym(handlesubdvm, "MSJavaHookMethod");
        LOGD("***end dlsym methond***");
    }
    else
    {
        LOGE("***open so file fail or can't find file!***");
    }

	main();
}


